package com.itlong.cloud.property.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.itlong.cloud.POJO.DTO.property.PropertyAddVisitorDTO;
import com.itlong.cloud.POJO.DTO.property.PropertyGetVisitorInfoDTO;
import com.itlong.cloud.POJO.DTO.smartcard.SmartCardQRCodeContentDTO;
import com.itlong.cloud.POJO.PO.*;
import com.itlong.cloud.POJO.VO.app.AppFloorDevicesVO;
import com.itlong.cloud.POJO.VO.app.AppMineRoomInfoVO;
import com.itlong.cloud.POJO.VO.miniprogram.MiniProgramVisitorInfoVO;
import com.itlong.cloud.POJO.VO.property.*;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.constants.RabbitMQConstant;
import com.itlong.cloud.constants.RedisConstant;
import com.itlong.cloud.enumerate.*;
import com.itlong.cloud.property.dao.IPropertyVisitorPassCodeRecordDao;
import com.itlong.cloud.property.service.IPropertyVisitorPassCodeRecordService;
import com.itlong.cloud.rabbitmq.config.MessageSender;
import com.itlong.cloud.service.RedisService;
import com.itlong.cloud.utils.data.handler.SqlUtil;
import com.itlong.cloud.utils.date.DateUtil;
import com.itlong.cloud.utils.encrypt.DesEncryptUtil;
import com.itlong.cloud.utils.file.UploadFileUtil;
import com.itlong.cloud.utils.node.JsonUtil;
import com.itlong.cloud.utils.page.PageByVisitor;
import com.itlong.cloud.utils.picture.QrcodeUtils;
import com.itlong.cloud.utils.random.LogicIdUtil;
import com.itlong.cloud.utils.random.RandomUtil;
import com.itlong.cloud.utils.words.StringHandlerUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.NoSuchProviderException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* <desc>
*      物业-访客密码业务处理接口
* </desc>
*
* @createDate 2018/06/28
*/
@Service
@RefreshScope
public class PropertyVisitorPassCodeRecordServiceImpl implements IPropertyVisitorPassCodeRecordService {
    private static final Logger LOG = LoggerFactory.getLogger(PropertyVisitorPassCodeRecordServiceImpl.class);

    @Autowired
    IPropertyVisitorPassCodeRecordDao iPropertyVisitorPassCodeRecordDao;

    @Autowired
    private MessageSender messageSender;

    @Autowired
    private RedisService redisService;
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private Lock writeLock;
    @PostConstruct
    public void init(){
        writeLock = lock.writeLock();
    }

    @Value("${" + PlatformConstants.FILE_FTP_HOST + "}")
    public String FILE_FTP_HOST;

    @Value("${" + PlatformConstants.FILE_FTP_PORT + "}")
    public String FILE_FTP_PORT;

    @Value("${" + PlatformConstants.FILE_FTP_USERNAME + "}")
    public String FILE_FTP_USERNAME;

    @Value("${" + PlatformConstants.FILE_FTP_PASSWORD + "}")
    public String FILE_FTP_PASSWORD;

    @Value("${" + PlatformConstants.FILE_ACCESS_URL + "}")
    public String FILE_ACCESS_URL;

    /**
     * <desc>
     *      添加访客
     * </desc>
     *
     * @param propertyAddVisitorDTO 访客密码记录实体类
     * @return
     * @throws Exception
     * @author Jiaqi.X
     * @createDate 2018/06/28
     */
    @Override
//    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public AppVisitorPassCodeRecordPO save(PropertyAddVisitorDTO propertyAddVisitorDTO) throws Exception {
        Map<String,Object> qrcodeConfigure = iPropertyVisitorPassCodeRecordDao.getVisitorConfigure(propertyAddVisitorDTO.getProjectId());
        String visitorQrCodeTimesRestrict = StringHandlerUtil.getNullOrStringForObject(qrcodeConfigure.get("visitorQrCodeTimesRestrict"));
        String chargeMode = StringHandlerUtil.getNullOrStringForObject(qrcodeConfigure.get("chargeMode"));
        String visitorTimeSetting = StringHandlerUtil.getNullOrStringForObject(qrcodeConfigure.get("visitorTimeSetting"));
        //如果次数为空或者大于10 默认为10
        if(StringUtils.isBlank(propertyAddVisitorDTO.getCountLimit()) && propertyAddVisitorDTO.getVisitorQrCodeUsableTimes() == null){
            propertyAddVisitorDTO.setCountLimit("1000");
        }else if(propertyAddVisitorDTO.getVisitorQrCodeUsableTimes()!=null){
            propertyAddVisitorDTO.setCountLimit(propertyAddVisitorDTO.getVisitorQrCodeUsableTimes().toString());
        }
        AppVisitorPassCodeRecordPO passPO=new AppVisitorPassCodeRecordPO();
        passPO.setIntervieweeName(propertyAddVisitorDTO.getIntervieweeName());
        passPO.setVisitorIdCard(propertyAddVisitorDTO.getVisitorIdCard());
        passPO.setBuildId(propertyAddVisitorDTO.getBuildId());
        passPO.setUnitId(propertyAddVisitorDTO.getUnitId());
        passPO.setRoomId(propertyAddVisitorDTO.getRoomId());
        passPO.setCreateTime(new Date());
        if(propertyAddVisitorDTO.getSourceType()==2){
            passPO.setSource(VisitorSourceTypeEnum.PROPERTY_APP.getType());
        }else{
            passPO.setSource(VisitorSourceTypeEnum.PROPERTY.getType());
        }
        passPO.setIdcardKey(propertyAddVisitorDTO.getIdcardKey());
        passPO.setTemporaryAuthDeviceUniques(propertyAddVisitorDTO.getDeviceUniques());
        passPO.setTemporaryAuthType(propertyAddVisitorDTO.getTemporaryAuthType()==null?0:propertyAddVisitorDTO.getTemporaryAuthType());
        if (!StringUtils.isBlank(propertyAddVisitorDTO.getPassId())) {
            PropertyGetVisitorInfoVO infoVO = iPropertyVisitorPassCodeRecordDao.getVisitorInfo(propertyAddVisitorDTO.getPassId());
            passPO.setVFaceId(infoVO.getVFaceId());
            passPO.setFacePicUrl(infoVO.getFacePicUrl());
        }
        boolean onDay = false;
        if(StringUtils.isNotBlank(propertyAddVisitorDTO.getEffectiveTime()) && propertyAddVisitorDTO.getEffectiveTime().equals("0")
                && (StringUtils.isNotBlank(visitorTimeSetting) && !"2".equals(visitorTimeSetting))){
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startStr = String.format("%s%s",DateUtil.fomatDate(passPO.getCreateTime(),DateUtil.YMDSQL)," 00:00:00");
            passPO.setStartTime(format.parse(startStr));
            String endStr = String.format("%s%s",DateUtil.fomatDate(passPO.getCreateTime(), DateUtil.YMDSQL)," 23:59:59");
            Map<String,Object> timeDifference = DateUtil.reckonDate(endStr,startStr);
            propertyAddVisitorDTO.setEffectiveTime(timeDifference.get("min")+"");
            onDay = true;
        }else if(StringUtils.isNotBlank(visitorTimeSetting) && "2".equals(visitorTimeSetting)){
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String startStr = String.format("%s%s",propertyAddVisitorDTO.getVisitTime()," 00:00:00");
            String endStr = String.format("%s%s",propertyAddVisitorDTO.getVisitTime()," 23:59:59");
            passPO.setStartTime(format.parse(startStr));
            passPO.setEndTime(format.parse(endStr));
        } else{
            //如果有效时间为空，默认为当前创建时间
            if(StringUtils.isBlank(propertyAddVisitorDTO.getEffectiveTime())){
                propertyAddVisitorDTO.setEffectiveTime("1440");
            }
            passPO.setStartTime(passPO.getCreateTime());
        }
        if(StringUtils.isBlank(propertyAddVisitorDTO.getPassId())) {
            passPO.setPassId(LogicIdUtil.bussinessId());
        }else{
           passPO.setPassId(propertyAddVisitorDTO.getPassId());
           passPO.setUpdateTime(new Date());
        }
        passPO.setVisitorName(propertyAddVisitorDTO.getVisitorName());
        passPO.setVisitorPhone(propertyAddVisitorDTO.getVisitorPhone());
        passPO.setStatus(DataStatusEnum.NORMAL.getType());
        passPO.setUserId(propertyAddVisitorDTO.getLoginUserId());
        String roomNum = "";
        if(StringUtils.isNotBlank(propertyAddVisitorDTO.getRoomId())){
            roomNum = iPropertyVisitorPassCodeRecordDao.getRoomNumByRoomId(propertyAddVisitorDTO.getRoomId());
        }
        passPO.setVisitorCause(propertyAddVisitorDTO.getVisitorCause());
        //云对讲机号 多个，号分隔
        StringBuffer deviceStr = new StringBuffer();
        Map<String,Object> cloudTalkMap=iPropertyVisitorPassCodeRecordDao.getCloudIntercomUniquesByBuildIdAndUnitId(propertyAddVisitorDTO);
        String cloudUniques = "";
        String cloudeviceUniques ="";
        String entranceUniques = "";
        String entranceDeviceUniques ="";
        if(cloudTalkMap!=null){
            cloudUniques= cloudTalkMap.get("deviceIds").toString();
            cloudeviceUniques= cloudTalkMap.get("deviceUniques").toString();
            deviceStr.append(String.format("%s%s",cloudeviceUniques,","));
        }
        //门禁机号 多个，号分隔
        Map<String,Object> entranceMap=iPropertyVisitorPassCodeRecordDao.getEntranceUniquesByBuildIdAndUnitId(propertyAddVisitorDTO);
        if(entranceMap!=null){
            entranceUniques= entranceMap.get("deviceIds").toString();
            entranceDeviceUniques= entranceMap.get("deviceUniques").toString();
            deviceStr.append(String.format("%s%s",entranceDeviceUniques,","));
        }
        //电梯机号 多个，号分隔
        String elevatorUniques=iPropertyVisitorPassCodeRecordDao.getElevatorUniquesByBuildIdAndUnitId(propertyAddVisitorDTO);
        StringBuffer stringBuffer = new StringBuffer();
        //在此处根据拜访房间的正背门来筛选相对应正背门电梯的权限
        if(StringUtils.isNotBlank(propertyAddVisitorDTO.getRoomId())){
            String roomDoorType = iPropertyVisitorPassCodeRecordDao.getRoomForDoorInfo(propertyAddVisitorDTO.getRoomId());
            if(StringUtils.isNotEmpty(elevatorUniques)){
                for(String deviceId : elevatorUniques.split(",")){
                    String liftDoorType = iPropertyVisitorPassCodeRecordDao.getElevatorDoorInfo(StringHandlerUtil.autlSupply(4,deviceId,"0"),propertyAddVisitorDTO.getProjectId());
                    //如果电梯是正门
                    String deviceUniqueElevator =  String.format("%s%s%s",propertyAddVisitorDTO.getProjectId(),"1",StringHandlerUtil.autlSupply(4,deviceId,"0"));
                    if((roomDoorType.equals("1") && liftDoorType.equals("1")) || (roomDoorType.equals("0") && liftDoorType.equals("0")) ||
                            (StringUtils.isNotEmpty(propertyAddVisitorDTO.getDeviceUniques()) && propertyAddVisitorDTO.getDeviceUniques().contains(deviceUniqueElevator))){
                        stringBuffer.append(deviceId+",");
                    }
                }
                if(StringUtils.isNotEmpty(stringBuffer.toString())){
                    stringBuffer.deleteCharAt(stringBuffer.lastIndexOf(","));
                    elevatorUniques = stringBuffer.toString();
                }else{
                    elevatorUniques = new String();
                }
            }
        }

        //处理访客的临时设备权限
        StringBuffer temporaryAuthDoor = new StringBuffer();
        StringBuffer temporaryAuthCloudTalk = new StringBuffer();
        List<AppFloorDevicesVO> elevatorTemporaryAuthList = new ArrayList<>();
        List<String> elevatorTemAutList = new ArrayList<>();
        Map<String,String> elevatorMap = new HashMap<>();
        String builds = propertyAddVisitorDTO.getBuildId();
        String units = propertyAddVisitorDTO.getUnitId();
        if(StringUtils.isNotBlank(propertyAddVisitorDTO.getRoomId())){
            passPO.setFloorNum(Integer.valueOf(roomNum.substring(0,2)).toString());
        }
        if(StringUtils.isNotEmpty(propertyAddVisitorDTO.getDeviceUniques())){
            Map<String,String> mainDoorElevator = new HashMap<>();
            Map<String,String> backDoorElevator = new HashMap<>();
            List<AppFloorDevicesVO> lists = propertyAddVisitorDTO.getLists();
            String[] deviceUniqueArr = propertyAddVisitorDTO.getDeviceUniques().split(",");
            for(String deviceUnique : deviceUniqueArr){
                Integer deviceType = Integer.parseInt(StringHandlerUtil.copySubStr(deviceUnique, 8, 1));
                switch (PropertyEquipTypeEnum.getByEquipType(deviceType)) {
                    case ENTRANCE:
                        entranceUniques= entranceUniques.isEmpty()?String.format("%s%s",entranceUniques,deviceUnique.substring(9,13)):String.format("%s%s%s",entranceUniques,",",deviceUnique.substring(9,13));
                        deviceStr.append(String.format("%s%s",deviceUnique,","));
                        temporaryAuthDoor.append(deviceUnique.substring(9,13)+",");
                        break;
                    case CLOUD_INTERCOM:
                        cloudUniques= cloudUniques.isEmpty()?String.format("%s%s",cloudUniques,deviceUnique.substring(9,13)):String.format("%s%s%s",cloudUniques,",",deviceUnique.substring(9,13));
                        deviceStr.append(String.format("%s%s",deviceUnique,","));
                        temporaryAuthCloudTalk.append(deviceUnique.substring(9,13)+",");
                        break;
                    case ELEVATOR:
                        String floorAuth = Integer.valueOf(roomNum.substring(0,2)).toString();
                        for(AppFloorDevicesVO devicesVO : lists){
                            if(deviceUnique.equals(devicesVO.getDeviceUnique())){
                                if(StringUtils.isEmpty(elevatorUniques)){
                                    elevatorUniques=deviceUnique.substring(9,13);
                                }else{
                                    elevatorUniques=String.format("%s%s%s",elevatorUniques,",",deviceUnique.substring(9,13));
                                }
                                elevatorTemAutList.add(deviceUnique);
                                elevatorTemporaryAuthList.add(devicesVO);
                                if(devicesVO.getLiftDoorType()==1){
                                    mainDoorElevator.put(deviceUnique.substring(9,13),devicesVO.getLiveFloor());
                                }else{
                                    backDoorElevator.put(deviceUnique.substring(9,13),devicesVO.getLiveFloor());
                                }
                                if(java.util.Arrays.asList(devicesVO.getLiveFloor().split(",")).contains(floorAuth)){
                                    elevatorMap.put(deviceUnique,devicesVO.getLiveFloor());
                                }else{
                                    //所拜访房间业主的该电梯设备没有所拜访房间的楼层权限则不拼接楼层权限
                                    List<AppFloorDevicesVO> listAll = propertyAddVisitorDTO.getListAll();
                                    int count = 0;
                                    for(AppFloorDevicesVO floorDevicesVO : listAll){
                                        if(floorDevicesVO.getDeviceUnique().equals(deviceUnique) &&
                                                java.util.Arrays.asList(floorDevicesVO.getLiveFloor().split(",")).contains(floorAuth)){
                                            Map<String,Object> tempMap = iPropertyVisitorPassCodeRecordDao.getBuildAndUnitBySn(String.format("%s%s%s",deviceUnique.substring(0,8),"0000",deviceUnique.substring(9,deviceUnique.length())));
                                            if(tempMap!=null && tempMap.containsKey("unitIds") && tempMap.get("unitIds").toString().contains(propertyAddVisitorDTO.getUnitId())){
                                                elevatorMap.put(deviceUnique,devicesVO.getLiveFloor().isEmpty()?floorAuth:devicesVO.getLiveFloor() +","+floorAuth);
                                                count++;
                                                break;
                                            }
                                        }
                                    }
                                    if(count==0){
                                        elevatorMap.put(deviceUnique,devicesVO.getLiveFloor());
                                    }else{
                                        elevatorMap.put(deviceUnique,devicesVO.getLiveFloor().isEmpty()?floorAuth:devicesVO.getLiveFloor() +","+floorAuth);
                                    }
                                }
                                Map<String,Object> buildAndUnit = iPropertyVisitorPassCodeRecordDao.getBuildAndUnitBySn(String.format("%s%s%s",deviceUnique.substring(0,8),"0000",deviceUnique.substring(9,deviceUnique.length())));
                                if(buildAndUnit!=null && !buildAndUnit.isEmpty()){
                                    builds = String.format("%s%s%s",builds,",",buildAndUnit.get("buildId").toString());
                                    units = String.format("%s%s%s",units,",",buildAndUnit.get("unitIds").toString());
                                }
                                break;
                            }
                        }
                        break;
                    default:
                        break;
                }
            }
            if(!mainDoorElevator.isEmpty()){
                passPO.setMainDoorElevatorAuth(JSONArray.toJSONString(mainDoorElevator));
            }
            if(!backDoorElevator.isEmpty()){
                passPO.setBackDoorElevatorAuth(JSONArray.toJSONString(backDoorElevator));
            }
        }
        passPO.setBuildIdTemporaryAuth(builds);
        passPO.setUnitIdTemporaryAuth(units);
        passPO.setOwnerAuthDeviceUnique(deviceStr.length()>0?deviceStr.substring(0,deviceStr.length()-1):"");

        //获取房间号的楼栋信息
        //如果没有设备权限直接返回null
        if(StringUtils.isNotBlank(cloudUniques) || StringUtils.isNotBlank(entranceUniques) || StringUtils.isNotBlank(elevatorUniques)) {
            String uniques = StringUtils.isNotBlank(cloudUniques) ? cloudUniques + "," : "";
            uniques += StringUtils.isNotBlank(entranceUniques) ? uniques + entranceUniques  : uniques;
            //为了防止门禁与云对讲机号重复，现对设备机号进行去重处理
            String[] allDeviceIds = StringHandlerUtil.splitString(uniques);
            Set<String> setDeviceIds = new HashSet<>();
            String deviceIds = "";
            for (String deviceId : allDeviceIds) {
                if (!deviceId.equals("null") && setDeviceIds.add(deviceId)) {
                    deviceIds += StringHandlerUtil.autlSupply(4,deviceId,"0") + ",";
                }
            }
            //设置门禁的id
            passPO.setDeviceId(StringUtils.isNotBlank(deviceIds) ? deviceIds.substring(0, deviceIds.length() - 1) : "");
            passPO.setUseNum(0);
            //生成二维码信息
            Map<String,Object> codeResult;
            if((StringUtils.isNotBlank(visitorQrCodeTimesRestrict) && visitorQrCodeTimesRestrict.equals("1"))||"2".equals(chargeMode) || "1".equals(visitorTimeSetting)){
                String count = propertyAddVisitorDTO.getVisitorQrCodeUsableTimes()==null?propertyAddVisitorDTO.getCountLimit():propertyAddVisitorDTO.getVisitorQrCodeUsableTimes().toString();
                codeResult = this.getNewQrCode(elevatorUniques, deviceIds, propertyAddVisitorDTO.getProjectId(), DateUtil.fomatDate(passPO.getStartTime()),
                        passPO.getFloorNum(), Integer.valueOf(propertyAddVisitorDTO.getEffectiveTime()),
                        elevatorTemAutList, elevatorMap,count,chargeMode);
            }else {
                codeResult = this.getQrCode(elevatorUniques, deviceIds, propertyAddVisitorDTO.getProjectId(), DateUtil.fomatDate(passPO.getStartTime()),
                        propertyAddVisitorDTO.getLoginUserId(), propertyAddVisitorDTO.getVisitorPhone(), Integer.valueOf(propertyAddVisitorDTO.getEffectiveTime()),
                        passPO.getFloorNum(), elevatorTemAutList, elevatorMap);
            }
            passPO.setQrcode(codeResult.get("qrcode").toString().toUpperCase());
            passPO.setVisitorUuid(codeResult.get("visitorUuid").toString());
            passPO.setMac(StringHandlerUtil.getNullOrStringForObject(codeResult.get("mac")));
            passPO.setBatch(codeResult.get("batch") != null ? Integer.valueOf(codeResult.get("batch").toString()) : 1);
        }else{
            passPO.setQrcode("00000000000000000000000000000000000000000000000000");
        }
        //生成二维码图片
        BufferedImage bim = QrcodeUtils.getQR_CODEBufferedImage(passPO.getQrcode(), BarcodeFormat.QR_CODE, 300, 300, QrcodeUtils.getDecodeHintType());
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(bim,"png",out);
        InputStream input = new ByteArrayInputStream(out.toByteArray());
        UploadFileUtil.UploadFile uploadFileUtil = new UploadFileUtil().new UploadFile(
                FILE_FTP_HOST,
                FILE_FTP_USERNAME,
                FILE_FTP_PASSWORD,
                FILE_FTP_PORT,
                input,
                "png",
                FILE_ACCESS_URL,
                FileCatalogEnum.VISITOR_PASS_QRCODE_FILE.getType()
        );
        Map<String, Object> resultMap = UploadFileUtil.uploadFile(uploadFileUtil);
        Boolean returnCode = (Boolean)resultMap.get("returnCode");
        if (returnCode == true){
            passPO.setQrcodeUrl(resultMap.get("accessPath").toString());
        }
        passPO.setProjectId(propertyAddVisitorDTO.getProjectId());
        //设置有效结束时间
        if(onDay){
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String endStr = String.format("%s%s",DateUtil.fomatDate(passPO.getCreateTime(), DateUtil.YMDSQL)," 23:59:59");
            passPO.setEndTime(format.parse(endStr));
        }else{
            //由于在后台配置自定义时间 若时长在25天和30天之间，DateUtil.addCurrentTime 计算结束时间会有问题，故在此做了兼容
            if(Integer.parseInt(propertyAddVisitorDTO.getEffectiveTime())>=36000){
                passPO.setEndTime(DateUtil.getAddDay(passPO.getStartTime(),Integer.valueOf(propertyAddVisitorDTO.getEffectiveTime())/60/24));
            }else if(StringUtils.isNotBlank(visitorTimeSetting) && "2".equals(visitorTimeSetting)){

            } else{
                passPO.setEndTime(DateUtil.addCurrentTime(passPO.getStartTime(),
                        Integer.valueOf(propertyAddVisitorDTO.getEffectiveTime()) * 60 * 1000));
            }
        }
        passPO.setNum(Integer.valueOf(propertyAddVisitorDTO.getCountLimit()));
        //判断项目配置信息 生成动态密码 0在线版 1离线版
        Integer otpOnline = iPropertyVisitorPassCodeRecordDao.getOtpOnlineByProjectId(propertyAddVisitorDTO.getProjectId());
        if(otpOnline == 0) {
            //在线版验证方式
            String random = StringHandlerUtil.autlSupply(4, RandomUtil.getRandomAround(9999, 0).toString(), "0");
            int repeat = 1;
            try {
                //获取写锁
                writeLock.lock();
                while (repeat > 0) {
                    //检查是否重复
                    repeat = iPropertyVisitorPassCodeRecordDao.checkRepeatPassword(random,
                            DateUtil.fomatDate(passPO.getStartTime(), DateUtil.YYYYMMDDHHMM),
                            DateUtil.fomatDate(passPO.getEndTime(), DateUtil.YYYYMMDDHHMM));
                    if (repeat > 0) {
                        random = StringHandlerUtil.autlSupply(4, RandomUtil.getRandomAround(9999, 0).toString(), "0");
                    }
                }
                passPO.setPassword(random);
            } catch (Exception e) {
                throw e;
            } finally {
                writeLock.unlock();
            }
            passPO.setType(DynamicPasswordTypeEnum.ONLINE.getType());
        }else{
            //脱机版验证方式
            //获取加密后的项目秘钥
            String encriptProjKey=StringHandlerUtil.bytesToHexStr(DesEncryptUtil.getQrcodeKey(DesEncryptUtil.QRCODE_INIT_KEY, propertyAddVisitorDTO.getProjectId()));
            //动态密码规则 楼层（03）+权限组号（01）+四位密码
            StringBuilder password = new StringBuilder(StringHandlerUtil.autlSupply(2,((Integer)Math.abs(Integer.valueOf(passPO.getFloorNum()))).toString(),"0"));
            //获取权限组号
            String unitGroupNum = iPropertyVisitorPassCodeRecordDao.getGroupNumByUnitId(propertyAddVisitorDTO.getUnitId());
            if(StringUtils.isNotBlank(unitGroupNum) && Integer.valueOf(unitGroupNum) <= 99){
                password.append(unitGroupNum);
            }else{
                password.append("00");
            }
            StringBuilder encriptValue = new StringBuilder(password.toString());
            encriptValue.append(DateUtil.fomatDate(passPO.getEndTime(),"yyMMdd"));
            //获取时间段
            List<String> times = DateUtil.getIntervalTimeList("00:00:00","23:59:59",30);
            for(Integer i = 0 ; i<times.size() ; i++){
                if(i == times.size() -1 ){
                    encriptValue.append("48");
                    break;
                }else if(DateUtil.formatStringToDate(times.get(i),"HH:mm:ss").getTime() <=
                        DateUtil.formatStringToDate(DateUtil.fomatDate(passPO.getEndTime(),"HH:mm:ss"),"HH:mm:ss").getTime()
                        && DateUtil.formatStringToDate(times.get(i+1),"HH:mm:ss").getTime() >=
                        DateUtil.formatStringToDate(DateUtil.fomatDate(passPO.getEndTime(),"HH:mm:ss"),"HH:mm:ss").getTime() ){
                    encriptValue.append(StringHandlerUtil.autlSupply(2,((Integer)(i+1)).toString(),"0"));
                    break;
                }
            }
            //备用字节
            encriptValue.append("0000");
            String des = DesEncryptUtil.getUserKey(encriptValue.toString(),encriptProjKey);
            String hex = des.substring(des.length()-6,des.length());
            hex=((Integer)Integer.parseInt(hex,16)).toString();
            password.append(hex.substring(hex.length()-4,hex.length()));
            passPO.setPassword(password.toString());
            passPO.setType(DynamicPasswordTypeEnum.OFFLINE.getType());
        }
        if(StringUtils.isBlank(propertyAddVisitorDTO.getPassId())) {
            passPO.setCheckOperator("系统");
            passPO.setCheckStatus(1);
            passPO.setOwnerCheckStatus(1);
            passPO.setCheckTime(new Date());
            passPO.setOwnerCheckTime(new Date());
            passPO.setPassNumber(RandomUtil.getRandomStringBySix(6));
            iPropertyVisitorPassCodeRecordDao.save(SqlUtil.durableData(passPO, PlatformConstants.TABLE_SAVE));
        }else{
            iPropertyVisitorPassCodeRecordDao.update(SqlUtil.durableData(passPO,PlatformConstants.TABLE_UPDATE));
        }
        Thread.sleep(500);
        //如果申请的访客有身份证序号,没有人脸信息,则发送云对讲,云电梯,云门禁指令
        if (propertyAddVisitorDTO.getIdcardKey() != null && !"".equals(propertyAddVisitorDTO.getIdcardKey())
                && (propertyAddVisitorDTO.getImageStr() == null || "".equals(propertyAddVisitorDTO.getImageStr()))) {
            List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
            JSONObject json = new JSONObject();
            json.put("userId", passPO.getPassId());
            json.put("projectId", propertyAddVisitorDTO.getProjectId());
            //云对讲
            DeviceBusinessChangeLogPO deviceBusinessChangeLogPO =
                    new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_USER_PROJECT, json,propertyAddVisitorDTO.getProjectId());
            changeLogPOS.add(deviceBusinessChangeLogPO);
            JSONObject dataJs = new JSONObject();
            dataJs.put("data",changeLogPOS);
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
            //云电梯
            DeviceBusinessElevatorChangeLogPO deviceBusinessElevatorChangeLogPO
                    = new DeviceBusinessElevatorChangeLogPO(propertyAddVisitorDTO.getProjectId(),
                    CloudElevatorChangeBusinessEnum.PUSH_USER_PROJECT,json.toJSONString());
            List<DeviceBusinessElevatorChangeLogPO> deviceElevatorChangeLogPOS = new ArrayList<>();
            deviceElevatorChangeLogPOS.add(deviceBusinessElevatorChangeLogPO);
            dataJs.put("data",deviceElevatorChangeLogPOS);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
            // 云门禁
            List<DeviceBusinessEntranceChangeLogPO> changeEntranceLogPOS = new ArrayList<>();
            changeEntranceLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_USER_PROJECT, json, propertyAddVisitorDTO.getProjectId()));
            dataJs.put("data", changeEntranceLogPOS);
            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
        }
        //发送临时权限数据
        List<DeviceBusinessChangeLogPO> changes = new ArrayList<>();
        List<DeviceBusinessElevatorChangeLogPO> elevatorChanges = new ArrayList<>();
        List<DeviceBusinessEntranceChangeLogPO> entranceChanges = new ArrayList<>();
        Map<String,Object> auth = new HashMap<>();
        auth.put("userId",passPO.getPassId());
        auth.put("projectId",passPO.getProjectId());
        auth.put("type",2);
        DeviceBusinessChangeLogPO po=new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_TEMP_AUTH,JsonUtil.toJSON(auth),passPO.getProjectId());
        changes.add(po);
        DeviceBusinessElevatorChangeLogPO elevatorPo = new DeviceBusinessElevatorChangeLogPO(passPO.getProjectId(),CloudElevatorChangeBusinessEnum.PUSH_TEMP_AUTH,JsonUtil.toJSON(auth));
        elevatorChanges.add(elevatorPo);
        DeviceBusinessEntranceChangeLogPO entrancePO = new DeviceBusinessEntranceChangeLogPO(passPO.getProjectId(),CloudEntranceChangeBusinessEnum.PUSH_TEMP_AUTH, JsonUtil.toJSON(auth));
        entranceChanges.add(entrancePO);
        JSONObject dataJs = new JSONObject();
        dataJs.put("data",changes);
        //发送云对讲业务指令
        messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE, RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
        dataJs.put("data",elevatorChanges);
        //推送云电梯业务指令
        messageSender.send(
                RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                JsonUtil.toJSON(dataJs),
                RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
        //发送云门禁业务指令
        dataJs.put("data",entranceChanges);
        messageSender.send(
                RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                JSON.toJSONString(dataJs),
                RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
        );
        return passPO;
    }

    /**
     * <desc>
     *      生成访客通行二维码
     * </desc>
     *
     * @param doorIds 门禁id（机号） 多个,号分隔
     * @param projectId 项目id
     * @return
     */
    private Map<String,Object> getNewQrCode(String elevators,String doorIds,String projectId,
                                            String startTime,String floorNum,
                                            Integer timeLimit,List<String> elevatorTemAutList,Map<String,String> elevatorMap,
                                            String countLimit,String chargeMode) throws NoSuchProviderException, ParseException {
        Map<String,Object> result = new HashMap<>();
        //用户有权限的且在当前楼栋的设备机号
        elevators = StringUtils.isEmpty(elevators)?"":elevators;
        StringBuilder authFloors=new StringBuilder(elevators);
        //开始拼接二维码
        StringBuilder heard=new StringBuilder("ITL:{L:");
        StringBuilder content = new StringBuilder();
        //协议版本 1Byte, Hex码
        content.append("V:"+AppQrcodeProtocolVersionEnum.INITIAL.getType()+",");
        //用户uid
        VisitorQrcodeVO vo = (VisitorQrcodeVO)redisService.getObject(RedisConstant.VISITOR_QRCODE_UID_REDIS_KEY + projectId, VisitorQrcodeVO.class);
        if(vo==null){
            vo = new VisitorQrcodeVO();
            vo.setUid(StringHandlerUtil.autlSupply(8,"1","0"));
            Date now = DateUtil.formatStringToDate(DateUtil.fomatDate(DateUtil.getAddDay(new Date(), 1), DateUtil.YMDSQL), DateUtil.YMDSQL);
            vo.setEndTime(now);
            redisService.set(RedisConstant.VISITOR_QRCODE_UID_REDIS_KEY+projectId,RedisConstant.VISITOR_QRCODE_UID_REDIS_CACHE_TIME,vo);
        }else{
            if(vo.getEndTime().getTime() > (new Date()).getTime()) {
                Integer count = (Integer.valueOf(vo.getUid()) + 1);
                vo.setUid(StringHandlerUtil.autlSupply(8,count.toString(),"0"));
            }else{
                vo.setUid(StringHandlerUtil.autlSupply(8,"1","0"));
                Date now = DateUtil.formatStringToDate(DateUtil.fomatDate(DateUtil.getAddDay(new Date(), 1), DateUtil.YMDSQL), DateUtil.YMDSQL);
                vo.setEndTime(now);
            }
            redisService.set(RedisConstant.VISITOR_QRCODE_UID_REDIS_KEY+projectId,RedisConstant.VISITOR_QRCODE_UID_REDIS_CACHE_TIME,vo);
        }
        content.append("U:"+vo.getUid()+",");
        //用户类型 1Byte，Hex码。 暂定0x11表示物业管理员；
        content.append("M:"+AppQrcodeUserTypeEnum.VISITOR.getType()+",");
        //房间编号
        content.append("H:00,");
        //批次号批次或流水号：“B:xxxx”其中“B”表示标识，批次值占用2个字节，用16进制表示0x0000—0xFFFF。
        content.append("I:0001,");
        //启用时间
        //生成日期 格式 yyMMddHHmm 由于设备时间与后台实际存在相差几分钟的情况，故生成二维码的有效开始时间提前十分钟
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.setTime(DateUtil.formatStringToDate(startTime,DateUtil.YYYYMMDDHHMM));
        beforeTime.add(Calendar.MINUTE, -10);// 10分钟之前的时间
        Date beforeD = beforeTime.getTime();
        startTime = DateUtil.fomatDate(beforeD,DateUtil.YYMMDDHHMM);
        String validCount;
        if(StringUtils.isNotBlank(countLimit)){
            validCount = StringHandlerUtil.autlSupply(4,countLimit!=null ? Integer.toHexString(Integer.valueOf(countLimit)).toUpperCase() : "01","0").toUpperCase();
        }else{
            validCount = "00";
        }
        timeLimit+=10;
        content.append("T:" +startTime+ ",");
        //有效时间 hex 码
        content.append("P:"+StringHandlerUtil.autlSupply(4,Integer.toHexString(Integer.valueOf(timeLimit)),"0").toUpperCase()+",");
        //有效次数 hex码
        content.append("S:"+validCount+",");
        if(validCount.length()>2){
            validCount=validCount.substring(2,4);
        }
        String value =startTime+StringHandlerUtil.autlSupply(4,Integer.toHexString(Integer.valueOf(timeLimit)),"0").toUpperCase()+validCount;
        String identifier="";
        //电梯门禁标识 如有电梯和门禁权限时为0x03；只有电梯而无门禁权限时为0x01；只有门禁权限时为0x02
        if(StringUtils.isNotBlank(doorIds) && StringUtils.isNotBlank(authFloors.toString())){
            identifier="03";
        }else if(StringUtils.isNotBlank(doorIds)){
            identifier="02";
        }else if(StringUtils.isNotBlank(authFloors.toString())){
            identifier="01";
        }else{
            identifier="00";
        }
        if(!identifier.equals("00")) {
            //转换得到电梯及门禁数组
            String doors[] = StringHandlerUtil.splitString(doorIds);
            String floors[] = StringHandlerUtil.splitString(authFloors.toString());
            //门禁
            if(!identifier.equals("01")) {
                //门禁数量 HEX码
                content.append("G:{");
                if (doors.length > 0 && doors.length < 255) {
                    String n1 = StringHandlerUtil.assembleQrcodeDeviceNum(doors);
                    String n2 = StringHandlerUtil.assembleNewDeviceNum(doors);
                    if(n1.length() > n2.length()) {
                        content.append("N2:" + n2);
                    }else{
                        content.append("N1:" + n1);
                    }
                }else{
                    content.append("N3:0");
                }
                content.append("},");
            }
            //电梯
            if(!identifier.equals("02")) {
                Map<String,Set<String>> builds = new HashMap<>();
                String[] commonFloor = new String[100];
                //对电梯按照楼层权限权限分组
                for(String f : floors){
                    //电梯权限 HEX码
                    String floorNo = "";
                    StringBuffer strBuffer = new StringBuffer();
                    if(elevatorTemAutList.contains(projectId + "1" + f)){
                        String temAuthFloor = elevatorMap.get(projectId + "1" + f).toString();
                        if(temAuthFloor.contains(",")){
                            String[] arr = temAuthFloor.split(",");
                            for(String str : arr) {
                                floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(str, projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0"));
                                if(StringUtils.isNotBlank(floorNo)){
                                    strBuffer.append(floorNo+",");
                                }
                            }
                            if(StringUtils.isNotBlank(floorNo)){
                                floorNo = strBuffer.deleteCharAt(strBuffer.length()-1).toString();
                            }
                            if(StringUtils.isNotEmpty(floorNo)) {
                                boolean add = false;
                                for (String k : builds.keySet()) {
                                    if (k.equals(floorNo)) {
                                        Set<String> deviceUniques = builds.get(k);
                                        deviceUniques.add(f);
                                        add = true;
                                    }
                                }
                                if (!add) {
                                    Set<String> deviceUniques = new HashSet<>();
                                    deviceUniques.add(f);
                                    builds.put(floorNo, deviceUniques);
                                }
                            }
                            continue;
                        }else{
                            floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(temAuthFloor, projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0"));
                        }
                    }else{
                        floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(floorNum, projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0"));
                    }

                    if(StringUtils.isNotEmpty(floorNo)) {
                        // 由于共享电梯项目 需求 上下都需收费，故将共同楼层权限加至二维码中，已和产品确认处理后只开放不点亮
                        commonFloor = StringHandlerUtil.splitString(iPropertyVisitorPassCodeRecordDao.getCommonFloorByDeviceUnique(projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0")));
                        if(commonFloor!=null && commonFloor.length>0 && StringUtils.isNotEmpty(chargeMode) && "2".equals(chargeMode)){
                            String commonFloorAuth = iPropertyVisitorPassCodeRecordDao.getCommonFloorAuthByDeviceUnique(commonFloor,projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0"));
                            LOG.info("查询数据commonFloor="+commonFloor +"deviceUnique = " + projectId + "1" +  StringHandlerUtil.autlSupply(4, f, "0"));
                            if (commonFloorAuth != null && commonFloorAuth != ""){
                                floorNo = floorNo +","+commonFloorAuth;
                            }
                        }
                        boolean add = false;
                        for (String k : builds.keySet()) {
                            if (k.equals(floorNo)) {
                                Set<String> deviceUniques = builds.get(k);
                                deviceUniques.add(f);
                                add = true;
                            }
                        }
                        if (!add) {
                            Set<String> deviceUniques = new HashSet<>();
                            deviceUniques.add(f);
                            builds.put(floorNo, deviceUniques);
                        }
                    }
                }
                for(String floor : builds.keySet()){
                    content.append("Q:{");
                    //所属单元电梯机号 HEX码
                    //设置机号权限N1：xxx
                    String n1  = StringHandlerUtil.assembleQrcodeDeviceNum(builds.get(floor).toArray(new String[builds.get(floor).size()]));
                    String n2 = StringHandlerUtil.assembleNewDeviceNum(builds.get(floor).toArray(new String[builds.get(floor).size()]));
                    if(n1.length() > n2.length()) {
                        content.append("N2:" + n2 + ",");
                    }else{
                        content.append("N1:" + n1 + ",");
                    }
                    //设置楼层号和直达楼层
                    n1 = StringHandlerUtil.assembleQrcodeDeviceNum(StringHandlerUtil.splitString(floor));
                    n2 = StringHandlerUtil.assembleNewDeviceNum(StringHandlerUtil.splitString(floor));
                    if(n1.length() > n2.length()) {
                        content.append("X2:" + n2 + ",");
                    }else{
                        content.append("X1:" + n1 + ",");
                    }
                    // 直达楼层 共享电梯模式下 二维码权限中需包含公共楼层权限
                    if(commonFloor!=null && commonFloor.length>0 && StringUtils.isNotEmpty(chargeMode) && "2".equals(chargeMode)){
                        floor = StringHandlerUtil.splitString(floor)[0];
                    }
                    if(StringUtils.isNotEmpty(chargeMode) && "1".equals(chargeMode)){
                        floor = null;
                    }
                    content.append("Y:" + ((StringUtils.isBlank(floor) || floor.split(",").length>1) ? "00" :
                            StringHandlerUtil.autlSupply(2, Integer.toHexString(Integer.valueOf(floor)).toUpperCase(), "0")) + "");
                    content.append("},");
                }
            }
        }
        result.put("floorNo",Integer.valueOf(floorNum));
        //获取项目秘钥
        String projectKey=iPropertyVisitorPassCodeRecordDao.getQrcodeProjectKey(projectId);
        String mac="K:"+DesEncryptUtil.newOwnerAndVisitorMacEncrypt(value, projectKey, content.toString());
        String qrcode = heard.toString()+ StringHandlerUtil.autlSupply(4,Integer.toHexString((content + mac).length()).toUpperCase(),"0") +","+content+mac+"}";
        result.put("qrcode",qrcode);
        result.put("mac",mac.substring(2,10));
        result.put("batch",1);
        result.put("visitorUuid",vo.getUid());
        return result;
    }

    /**
     * <desc>
     *      生成访客通行二维码
     * </desc>
     *
     * @param doorIds 门禁id（机号） 多个,号分隔
     * @param projectId 项目id
     * @param userId 用户id
     * @param phoneNum 当前用户手机号
     * @return
     */
    private Map<String,Object> getQrCode(String elevatorUniques,String doorIds,String projectId,
                                         String startTime,String userId,String phoneNum,Integer timeLimit,String floorNum,List<String> elevatorTemAutList,Map<String,String> elevatorMap) throws NoSuchProviderException, ParseException {
        Map<String,Object> result = new HashMap<>();
        //开始拼接二维码
        StringBuffer qrcode=new StringBuffer("");
        //协议版本 1Byte, Hex码 偶数代表业主，奇数代表访客
        qrcode.append(AppQrcodeProtocolVersionEnum.SECOND.getType());
        //用户类型 1Byte，Hex码。 暂定0x11表示物业管理员；
        qrcode.append(AppQrcodeUserTypeEnum.OWNER.getType());
        //用户UID 目前生成规则为用户手机号 不足6btye末尾补0
//        qrcode.append(StringHandlerUtil.autlSupplyLast(12,phoneNum,"0"));
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.YEAR, 10);
        String random = ((Long)calendar.getTime().getTime()).toString();
        String visitorUuid = random.substring(random.length() - 12 ,random.length());
        qrcode.append(visitorUuid);
        //生成日期 格式 yyMMddHHmm 由于设备时间与后台实际存在相差几分钟的情况，故生成二维码的有效开始时间提前十分钟
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.setTime(DateUtil.formatStringToDate(startTime,DateUtil.YYYYMMDDHHMM));
        beforeTime.add(Calendar.MINUTE, -10);// 10分钟之前的时间
        Date beforeD = beforeTime.getTime();
        startTime = DateUtil.fomatDate(beforeD,DateUtil.YYMMDDHHMM);
        qrcode.append(startTime);
        //流水号：1Byte，Hex码
        String cacheKey= RedisConstant.REDIS_APP_VISITOR_QRCODE_SERIAL_NUMBER_CACHE+userId+ DateUtil.fomatDate(new Date(), DateUtil.YYMMDD);
        Integer serialNumber=(Integer)redisService.getObject(cacheKey, Integer.class);
        if(serialNumber!=null){
            qrcode.append(StringHandlerUtil.autlSupply(2,Integer.toHexString(serialNumber).toUpperCase(),"0"));
        }else{
            serialNumber=1;
            qrcode.append(StringHandlerUtil.autlSupply(2,Integer.toHexString(serialNumber).toUpperCase(),"0"));
        }
        redisService.set(cacheKey, RedisConstant.REDIS_APP_VISITOR_QRCODE_SERIAL_NUMBER_CACHE_TIME, Integer.valueOf(serialNumber)+1);
        //有效时间 hex 码
        if(timeLimit==null) {
            qrcode.append("90");
        }else{
            qrcode.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(timeLimit / 10),"0").toUpperCase());
        }
        //有效次数 hex码
        qrcode.append("00");
        String identifier="";
        //电梯门禁标识 如有电梯和门禁权限时为0x03；只有电梯而无门禁权限时为0x01；只有门禁权限时为0x02
        if(StringUtils.isNotBlank(doorIds) && StringUtils.isNotBlank(elevatorUniques)){
            qrcode.append("03");
            identifier="03";
        }else if(StringUtils.isNotBlank(doorIds)){
            qrcode.append("02");
            identifier="02";
        }else if(StringUtils.isNotBlank(elevatorUniques)){
            qrcode.append("01");
            identifier="01";
        }else{
            qrcode.append("00");
            identifier="00";
        }
        if(!identifier.equals("00")) {
            //转换得到电梯及门禁数组
            String doors[] = StringHandlerUtil.splitString(doorIds);
            String floors[] = StringHandlerUtil.splitString(elevatorUniques);
            //门禁
            if(!identifier.equals("01")) {
                //门禁数量 HEX码
                qrcode.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(doors.length).toUpperCase(), "0"));
                //门禁机号 HEX码
                qrcode.append(StringHandlerUtil.assembleDeviceNum(doors));
            }
            //电梯
            if(!identifier.equals("02")) {
                Map<String,Set<String>> builds = new HashMap<>();
                //对电梯按照楼层权限权限分组
                for(String f : floors){
                    //电梯权限 HEX码

                    String floorNo = null;
                    StringBuffer strBuffer = new StringBuffer();
                    if(elevatorTemAutList.contains(projectId + "1" + StringHandlerUtil.autlSupply(4,f,"0"))){
                        String temAuthFloor = elevatorMap.get(projectId + "1" + StringHandlerUtil.autlSupply(4,f,"0")).toString();
                        if(temAuthFloor.contains(",")){
                            String[] arr = temAuthFloor.split(",");
                            for(String str : arr) {
                                floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(str, projectId + "1" + StringHandlerUtil.autlSupply(4, f, "0"));
                                if(StringUtils.isNotBlank(floorNo)){
                                    strBuffer.append(floorNo+",");
                                }
                            }
                            if(StringUtils.isNotBlank(floorNo)){
                                floorNo = strBuffer.deleteCharAt(strBuffer.length()-1).toString();
                            }
                            if(StringUtils.isNotEmpty(floorNo)) {
                                boolean add = false;
                                for (String k : builds.keySet()) {
                                    if (k.equals(floorNo)) {
                                        Set<String> deviceUniques = builds.get(k);
                                        deviceUniques.add(f);
                                        add = true;
                                    }
                                }
                                if (!add) {
                                    Set<String> deviceUniques = new HashSet<>();
                                    deviceUniques.add(f);
                                    builds.put(floorNo, deviceUniques);
                                }
                            }
                            continue;
                        }else{
                            floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(temAuthFloor, projectId + "1" + StringHandlerUtil.autlSupply(4,f,"0"));
                        }
                    }else{
                        floorNo = iPropertyVisitorPassCodeRecordDao.getFloorAuthByFloorNumAndDeviceUnique(floorNum, projectId + "1" + StringHandlerUtil.autlSupply(4,f,"0"));
                    }

                    if(StringUtils.isNotEmpty(floorNo)) {
                        boolean add = false;
                        for (String k : builds.keySet()) {
                            if (k.equals(floorNo)) {
                                Set<String> deviceUniques = builds.get(k);
                                deviceUniques.add(f);
                                add = true;
                            }
                        }
                        if (!add) {
                            Set<String> deviceUniques = new HashSet<>();
                            deviceUniques.add(f);
                            builds.put(floorNo, deviceUniques);
                        }
                    }
                }
                //有权限的电梯楼栋单元数量 最多8个单元 超过8个单元按拥有所有电梯权限处理
                qrcode.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(builds.keySet().size()).toUpperCase(), "0"));
                for(String floor : builds.keySet()){
                    //所属单元电梯数量 HEX 码
                    qrcode.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(builds.get(floor).size()).toUpperCase(), "0"));
                    //所属单元电梯机号 HEX码
                    qrcode.append(StringHandlerUtil.assembleDeviceNum(builds.get(floor).toArray(new String[builds.get(floor).size()])));
                    result.put("floorNo",floorNum);
                    //设置有权限的楼层数量
                    qrcode.append(StringHandlerUtil.autlSupply(2, Integer.toHexString(floor.split(",").length).toUpperCase(), "0"));
                    //设置楼层号和直达楼层
                    qrcode.append(StringHandlerUtil.assembleDeviceNum(floor.split(",")));
                    qrcode.append((StringUtils.isBlank(floor) || floor.split(",").length>1) ? "00" : StringHandlerUtil.autlSupply(2, Integer.toHexString(Integer.valueOf(floor)).toUpperCase(), "0"));
                }
            }
        }
        String value=qrcode.substring(16,32);
        //获取项目秘钥
        String projectKey=iPropertyVisitorPassCodeRecordDao.getQrcodeProjectKey(projectId);
//        LOG.info(String.format("【访客二维码数据监控】：projectId:%s,value:%s,projectKey:%s,qrcode:%s,mac:%s",projectId,value,projectKey,qrcode.toString()
//                , DesEncryptUtil.ownerAndVisitorMacEncrypt(value, projectKey, qrcode.toString())));
        qrcode.append(DesEncryptUtil.ownerAndVisitorMacEncrypt(value, projectKey, qrcode.toString()));
        result.put("qrcode",qrcode);
        result.put("visitorUuid",visitorUuid);
        result.put("mac",qrcode.substring(qrcode.length()-8,qrcode.length()));
        result.put("batch",1);
        return result;
    }

    /**
     * <desc>
     *     访客列表
     * <desc/>
     *
     *@param  visitorInfoDTO  分页查询访客列表
     * @return  MessageVO 标准格式化响应结果
     * @author JuGuang.S
     * @createDate 2018/06/28
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PageByVisitor<PropertyVisitorInfoVO> getVisitorInfoByPage(PropertyGetVisitorInfoDTO visitorInfoDTO) throws Exception {
        Map<String, Object> params = SqlUtil.convertBeanToMapParams(visitorInfoDTO);
        params.put("projectId", visitorInfoDTO.getProjectId());

        PageByVisitor<PropertyVisitorInfoVO> page = new PageByVisitor<>();
        page.getPage().setPageSize(visitorInfoDTO.getPageSize());
        page.getPage().setCurrentPage(visitorInfoDTO.getCurrentPage());
        params.put("currentPage", page.getPage().getStartSlip());
        params.put("pageSize", page.getPage().getPageSize());

        List<PropertyVisitorInfoVO> visitorInfoList = iPropertyVisitorPassCodeRecordDao.getVisitorInfoByPage(params);
        for(PropertyVisitorInfoVO infoVO : visitorInfoList){
            if(infoVO.getSource()==1 || infoVO.getSource()==4 || infoVO.getSource()==5 || (infoVO.getSource()==2 && StringUtils.isNotEmpty(infoVO.getRoomId()))){
               String adressName = iPropertyVisitorPassCodeRecordDao.getAdressByRoomId(infoVO.getRoomId());
               infoVO.setAddress(adressName);
            }

            if(infoVO.getSource()==2 && StringUtils.isEmpty(infoVO.getRoomId())){
                String adressNameStr = iPropertyVisitorPassCodeRecordDao.getAdressByUnitId(infoVO.getPassId(),infoVO.getUnitId());
                infoVO.setAddress(adressNameStr);
            }
        }
        Integer count = iPropertyVisitorPassCodeRecordDao.getVisitorInfoCount(params);

        page.setRows(visitorInfoList, count);
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");

        page.setVisitorCount(iPropertyVisitorPassCodeRecordDao.getVisitorDayCount(df.format(new Date()),visitorInfoDTO.getProjectId()));
        return page;
    }

    /**
     * <desc>
     *     根据访客ID获取访客信息
     * <desc/>
     *
     *@param  passId  访客ID
     * @return  PropertyGetVisitorInfoVO 访客信息VO
     * @author JuGuang.S
     * @createDate 2018/06/29
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PropertyGetVisitorInfoVO getVisitorInfo(String passId) throws Exception {
        PropertyGetVisitorInfoVO infoVO = iPropertyVisitorPassCodeRecordDao.getVisitorInfo(passId);
        if(infoVO.getSource()==1 || infoVO.getSource()==4 || (infoVO.getSource()==2 && StringUtils.isNotEmpty(infoVO.getRoomId()))){
            String adressName = iPropertyVisitorPassCodeRecordDao.getAdressByRoomId(infoVO.getRoomId());
            infoVO.setAddress(adressName);
        }

        if(infoVO.getSource()==2 && StringUtils.isEmpty(infoVO.getRoomId())){
            String adressNameStr = iPropertyVisitorPassCodeRecordDao.getAdressByUnitId(infoVO.getPassId(),infoVO.getUnitId());
            infoVO.setAddress(adressNameStr);
        }
        return infoVO;
    }

    /**
     * <desc>
     *     根据访客ID删除访客信息
     * <desc/>
     *
     *@param  projectId  项目编号
     *@param  visitorArr  访客ID多个以逗号分隔
     * @return
     * @author JuGuang.S
     * @createDate 2018/06/29
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void deleteVisitorInfo(String projectId, String[] visitorArr) throws Exception {
        for (String passId:visitorArr) {
            List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
            JSONObject json = new JSONObject();
            json.put("userId", passId);//访客推送的时候使用V- + 访客记录编号  来区分业主还是访客
            json.put("projectId", projectId);
            DeviceBusinessChangeLogPO deviceBusinessChangeLogPO =
                    new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_USER_PROJECT, json,projectId);
            changeLogPOS.add(deviceBusinessChangeLogPO);
            JSONObject dataJs = new JSONObject();
            dataJs.put("data",changeLogPOS);
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                    JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);

            //云电梯
            DeviceBusinessElevatorChangeLogPO deviceBusinessElevatorChangeLogPO
                    = new DeviceBusinessElevatorChangeLogPO(projectId,
                    CloudElevatorChangeBusinessEnum.PUSH_USER_PROJECT,json.toJSONString());
            List<DeviceBusinessElevatorChangeLogPO> deviceElevatorChangeLogPOS = new ArrayList<>();
            deviceElevatorChangeLogPOS.add(deviceBusinessElevatorChangeLogPO);
            dataJs.put("data",deviceElevatorChangeLogPOS);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);

            // 云门禁
            List<DeviceBusinessEntranceChangeLogPO> changeEntranceLogPOS = new ArrayList<>();
            changeEntranceLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_USER_PROJECT, json, projectId));
            dataJs.put("data", changeEntranceLogPOS);
            //发送云门禁指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(dataJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
            //发送临时权限数据
            List<DeviceBusinessChangeLogPO> changes = new ArrayList<>();
            List<DeviceBusinessElevatorChangeLogPO> elevatorChanges = new ArrayList<>();
            List<DeviceBusinessEntranceChangeLogPO> entranceChanges = new ArrayList<>();
            Map<String, Object> auth = new HashMap<>();
            auth.put("userId", passId);
            auth.put("projectId", projectId);
            auth.put("type", 2);
            DeviceBusinessChangeLogPO po = new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_TEMP_AUTH, JsonUtil.toJSON(auth), projectId);
            changes.add(po);
            DeviceBusinessElevatorChangeLogPO elevatorPo = new DeviceBusinessElevatorChangeLogPO(projectId, CloudElevatorChangeBusinessEnum.PUSH_TEMP_AUTH, JsonUtil.toJSON(auth));
            elevatorChanges.add(elevatorPo);
            DeviceBusinessEntranceChangeLogPO entrancePO = new DeviceBusinessEntranceChangeLogPO(projectId, CloudEntranceChangeBusinessEnum.PUSH_TEMP_AUTH, JsonUtil.toJSON(auth));
            entranceChanges.add(entrancePO);
            JSONObject pushJs = new JSONObject();
            pushJs.put("data", changes);
            //发送云对讲业务指令
            messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE, JsonUtil.toJSON(pushJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE, RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);
            pushJs.put("data", elevatorChanges);
            //推送云电梯业务指令
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                    JsonUtil.toJSON(pushJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);
            //发送云门禁业务指令
            pushJs.put("data", entranceChanges);
            messageSender.send(
                    RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                    JSON.toJSONString(pushJs),
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                    RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
            );
        }
        iPropertyVisitorPassCodeRecordDao.deleteVisitorInfo(visitorArr);
    }

    /**
     * <desc>
     *     根据访客ID获取访客短信需要信息
     * <desc/>
     *
     *@param  passId
     * @return
     * @author JuGuang.S
     * @createDate 2018/06/29
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public PropertyVisitorSendMessageVO getVisitorMessage(String passId) throws Exception {
        PropertyVisitorSendMessageVO messageVO = iPropertyVisitorPassCodeRecordDao.getVisitorMessage(passId);
        if(messageVO.getSource()==1){
            String adressName = iPropertyVisitorPassCodeRecordDao.getAdressByRoomIdAndPassId(messageVO.getRoomId(),messageVO.getPassId());
            messageVO.setAddress(adressName);
        }

        if(messageVO.getSource()==2 || messageVO.getSource()==5){
            String adressNameStr = iPropertyVisitorPassCodeRecordDao.getAdressByUnitIdAndProject(messageVO.getPassId(),messageVO.getUnitId());
            messageVO.setAddress(adressNameStr);
        }
        return messageVO;
    }

    /**
     * <desc>
     *     根据访客ID更新发送短信的次数
     * <desc/>
     *
     *@param  passId  访客ID多个以逗号分隔
     * @return
     * @author JuGuang.S
     * @createDate 2018/07/02
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void updateSendMssCount(String passId) throws Exception {
        iPropertyVisitorPassCodeRecordDao.updateSendMssCount(passId);
    }

    /**
     * <desc>
     *     查询APP添加访客未向物业推送消息的访客信息
     * <desc/>
     *
     *@param
     * @return
     * @author JuGuang.S
     * @createDate 2018/07/04
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public List<PropertyVisitorInfoByPushVO> getVisitorInfoByPush() throws Exception {
        List<PropertyVisitorInfoByPushVO> infoByPushVOSList = iPropertyVisitorPassCodeRecordDao.getVisitorInfoByPush();
        for(PropertyVisitorInfoByPushVO infoVO : infoByPushVOSList){
            if(infoVO.getSource()==1){
                String adressName = iPropertyVisitorPassCodeRecordDao.getAdressByRoomId(infoVO.getRoomId());
                infoVO.setAddress(adressName);
            }

            if(infoVO.getSource()==2){
                String adressNameStr = iPropertyVisitorPassCodeRecordDao.getAdressByUnitId(infoVO.getPassId(),infoVO.getUnitId());
                infoVO.setAddress(adressNameStr);
            }
        }
        return infoByPushVOSList;
    }

    /**
     * <desc>
     *     查询APP添加访客未向物业推送消息的访客信息
     * <desc/>
     *
     *@param
     * @return
     * @author JuGuang.S
     * @createDate 2018/07/04
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void updatePushStatus(String[] passId) throws Exception {
        iPropertyVisitorPassCodeRecordDao.updatePushStatus(passId);
    }

    /**
     * <desc>
     *     定时刷新访客表修改所有物业系统未在线时未推送消息的状态改为已推送，其定时刷新的时间须迟于VisitorPushMessageTimeTask.
     * <desc/>
     *
     *@param
     * @return
     * @author JuGuang.S
     * @createDate 2018/07/10
     */
    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void updateNotPushMessageStatus() throws Exception {
        iPropertyVisitorPassCodeRecordDao.updateNotPushMessageStatus();
    }

    /**
     * <desc>
     *      访客单审批
     * </desc>
     * @param passId 访客单ID
     * @param checkStatus 物业审核状态 1代表审批通过 2代表审批拒绝
     * @param type 1代表业主 2代表物业
     * @return
     * @author JuGuang.S
     * @createDate 2019/04/25
     */
    @Override
    public Integer propertyCheckVisitor(String passId, Integer checkStatus,String loginUserId,Integer type) throws Exception{
        //根据passid获取当前项目的审批配置信息
        Map<String,Object> map = iPropertyVisitorPassCodeRecordDao.getProjectInfoByPassId(passId);

        if(type == 1 && map.get("miniVisitorOwner").toString().equals("1") && map.get("miniVisitorProperty").toString().equals("1")){
            return iPropertyVisitorPassCodeRecordDao.OwnerCheckVisitor(passId,checkStatus,loginUserId);
        }else if(type == 1 && map.get("miniVisitorOwner").toString().equals("1") && map.get("miniVisitorProperty").toString().equals("0")){
            if(checkStatus == 1){
                this.sendMessage(passId,map.get("projectId").toString());
            }
            return iPropertyVisitorPassCodeRecordDao.OwnerCheckVisitor(passId,checkStatus,loginUserId);
        }else if(type == 1 && map.get("miniVisitorOwner").toString().equals("0") && map.get("miniVisitorProperty").toString().equals("1")){
            return iPropertyVisitorPassCodeRecordDao.OwnerCheckVisitor(passId,checkStatus,loginUserId);
        } else{
            if(checkStatus == 1){
                this.sendMessage(passId,map.get("projectId").toString());
            }
            return iPropertyVisitorPassCodeRecordDao.propertyCheckVisitor(passId,checkStatus,loginUserId);
        }


    }

    /**
     * <desc>
     *      向设备推送访客人脸信息
     * </desc>
     * @param passId 访客单ID
     * @param projectId 项目编号
     * @return
     * @author JuGuang.S
     * @createDate 2019/05/21
     */
    public void sendMessage(String passId,String projectId) throws Exception{
        List<DeviceBusinessChangeLogPO> changeLogPOS = new ArrayList<>();
        JSONObject json = new JSONObject();
        json.put("userId", passId);//访客推送的时候使用V- + 访客记录编号  来区分业主还是访客
        json.put("projectId", projectId);
        DeviceBusinessChangeLogPO deviceBusinessChangeLogPO =
                new DeviceBusinessChangeLogPO(SmartCommunityEnum.PUSH_USER_PROJECT, json,projectId);
        changeLogPOS.add(deviceBusinessChangeLogPO);
        JSONObject dataJs = new JSONObject();
        dataJs.put("data",changeLogPOS);
        //发送云对讲指令
        messageSender.send(RabbitMQConstant.RABBITMQ_HANDLE_SMART_COMMUNITY_ORDERS_QUEUE,
                JsonUtil.toJSON(dataJs), RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_EXCHANGE,
                RabbitMQConstant.RABBITMQ_SMART_COMMUNITY_ORDERS_ROUTING_KEY);

        //云电梯
        DeviceBusinessElevatorChangeLogPO deviceBusinessElevatorChangeLogPO
                = new DeviceBusinessElevatorChangeLogPO(projectId,
                CloudElevatorChangeBusinessEnum.PUSH_USER_PROJECT,json.toJSONString());
        List<DeviceBusinessElevatorChangeLogPO> deviceElevatorChangeLogPOS = new ArrayList<>();
        deviceElevatorChangeLogPOS.add(deviceBusinessElevatorChangeLogPO);
        dataJs.put("data",deviceElevatorChangeLogPOS);
        messageSender.send(
                RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ELEVATOR_CHANGE_BUSINESS_QUEUE,
                JsonUtil.toJSON(dataJs),
                RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_EXCHANGE,
                RabbitMQConstant.RABBITMQ_CLOUD_ELEVATOR_CHANGE_BUSINESS_ROUTING_KEY);

        // 云门禁
        List<DeviceBusinessEntranceChangeLogPO> changeEntranceLogPOS = new ArrayList<>();
        changeEntranceLogPOS.add(new DeviceBusinessEntranceChangeLogPO(CloudEntranceChangeBusinessEnum.PUSH_USER_PROJECT, json, projectId));
        dataJs.put("data", changeEntranceLogPOS);
        //发送云门禁指令
        messageSender.send(
                RabbitMQConstant.RABBITMQ_HANDLE_CLOUD_ENTRANCE_CHANGE_BUSINESS_QUEUE,
                JSON.toJSONString(dataJs),
                RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_EXCHANGE,
                RabbitMQConstant.RABBITMQ_CLOUD_ENTRANCE_CHANGE_BUSINESS_ROUTING_KEY
        );
    }

    /**
     * <desc>
     *     根据房屋编号模糊查询房间
     * <desc/>
     *
     *@param  unitId  单元编号
     *@param  roomNum  房间编号
     * @return  MessageVO 标准格式化响应结果
     * @author Qiang.S
     * @createDate 2019/05/14
     */
    @Override
    public List<AppMineRoomInfoVO> getRoomInfoByNum(String unitId, String roomNum) {
        return iPropertyVisitorPassCodeRecordDao.getRoomInfoByNum(unitId,roomNum);
    }

    /**
     * <desc>
     *      获取项目访客配置
     * </desc>
     *
     * @param projectId
     * @return
     * @author Jiaqi.X
     * @createDate 2020/05/22
     */
    @Override
    public Map<String, Object> getVisitorConfigure(String projectId) {
        return iPropertyVisitorPassCodeRecordDao.getVisitorConfigure(projectId);
    }

    /**
     * <desc>
     *      根据passId获取访客具体数据
     * </desc>
     *
     * @param passId 访客单ID
     * @return
     * @author Juguang.S
     * @createDate 2020/01/13
     */
    @Override
    public AppVisitorPassCodeRecordPO getVisitorByRenewVisitor(String passId) throws Exception {
        return iPropertyVisitorPassCodeRecordDao.getVisitorByRenewVisitor(passId);
    }

    /**
     * <desc>
     *      重新访问注册人脸失败，则需将旧数据恢复
     * </desc>
     *
     * @param oldPO 旧访客数据
     * @return
     * @author Juguang.S
     * @createDate 2020/01/13
     */
    @Override
    public void update(AppVisitorPassCodeRecordPO oldPO) throws Exception {
        iPropertyVisitorPassCodeRecordDao.update(SqlUtil.durableData(oldPO,PlatformConstants.TABLE_UPDATE));
    }

    /**
     * <desc>
     *      获取访客时间限制信息
     * </desc>
     *
     * @param projectId 项目编号
     * @return
     * @author Juguang.S
     * @createDate 2020/09/15
     */
    @Override
    public Map<String,Object> getVisitorTimeInfo(String projectId) throws Exception {
        Map<String,Object> map = iPropertyVisitorPassCodeRecordDao.getVisitorTimeInfo(projectId);
        if(map!=null && "2".equals(map.get("visitorTimeSetting").toString())){
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        Date d = sdf.parse("2021-12-28".trim());
            Date d = new Date();
            int count = DateUtil.differentDays(d,DateUtil.getAddMonth(d,1));
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            // 定义数组
            String[]time1=new String[32];
            Map<String,List<String>> monthMap = new HashMap<>();
            Map<String,Object> yearMap = new HashMap<>();
            List<Map<String,Object>> yearList = new ArrayList<>();

            Set<String> set = new HashSet<>();
            Set<String> set1 = new HashSet<>();
            for(int i=0;i<=count;i++){
                Date date = d;
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                calendar.set(Calendar.DATE, calendar.get(Calendar.DATE) + i);
                // 设置为前i天 
                date = calendar.getTime();
                //将获取的日期添加的数组
                time1[count-i]=dateFormat.format(date);
                List<String> dateList = new ArrayList<>();
                set.add(time1[count-i].substring(0,7));
                set1.add(time1[count-i].substring(0,5));
                if(monthMap.containsKey(time1[count-i].substring(5,7))){
                    monthMap.get(time1[count-i].substring(5,7)).add(time1[count-i].substring(8,10)+"日");
                    monthMap.put(time1[count-i].substring(5,7),monthMap.get(time1[count-i].substring(5,7)));
                }else{
                    dateList.add(time1[count-i].substring(8,10)+"日");
                    monthMap.put(time1[count-i].substring(5,7),dateList);
                }
            }
            if(set1.size()==2){
                for (Map.Entry<String,List<String>> entry : monthMap.entrySet()){
                    for(String str : set){
                        Map<String,List<String>> oldMonthMap = new HashMap<>();
                        if(str.substring(5,7).contains(entry.getKey())){
                            oldMonthMap.put(entry.getKey(),entry.getValue());
                            yearMap.put(str.substring(0,4),oldMonthMap);
                        }
                        set.remove(str);
                        break;
                    }

                }
            }else{
                for(String str : set){
                    yearMap.put(str.substring(0,4),monthMap);
                }
            }
            for (Map.Entry<String,Object> entry : yearMap.entrySet()){
                Map<String,Object> newYearMap = new HashMap<>();
                List<Map<String,Object>> monthList = new ArrayList<>();
                Map<String,Object> entry1 = (Map<String, Object>) entry.getValue();
                for (Map.Entry<String,Object> entry2 : entry1.entrySet()){
                    Map<String,Object> monthDayMap = new HashMap<>();
                    monthDayMap.put("month",entry2.getKey()+"月");
                    monthDayMap.put("dayList",entry2.getValue());
                    monthList.add(monthDayMap);
                }
                newYearMap.put("year",entry.getKey()+"年");
                newYearMap.put("monthList",monthList);
                yearList.add(newYearMap);
            }
            map.put("dateList",yearList);
        }

        return map;
    }

    /**
     * <desc>
     *      获取访客二维码内容
     * </desc>
     *
     * @param visitorId 访客id
     * @return
     * @Author Zhu.yj
     * @createDate  2021/6/2
     */
    @Override
    public MiniProgramVisitorInfoVO getQRCodeContent(String visitorId) throws Exception {

        MiniProgramVisitorInfoVO miniProgramVisitorInfoVO = new MiniProgramVisitorInfoVO();

        SmartCardQRCodeContentDTO smartCardQRCodeContentDTO = (SmartCardQRCodeContentDTO) redisService.getObject(RedisConstant.SMARTCARD_VISITOR_QR_CODE_CONTENT_CACHE_KEY + visitorId, SmartCardQRCodeContentDTO.class);
        if (smartCardQRCodeContentDTO == null){
            //当缓存过期时，线下平台访客二维码肯定过期，直接返回错误信息
            return null;
        }
        //缓存未过期，判断访客二维码是否已过有效期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateUtil.formatStringToDate(smartCardQRCodeContentDTO.getStartDate(), DateUtil.YYMMDDHHMM));
        miniProgramVisitorInfoVO.setStartTime(DateUtil.format(calendar, DateUtil.YYYYMMDDHHMM));
        calendar.add(Calendar.MINUTE, smartCardQRCodeContentDTO.getValidTime());
        //已经失效
        if (calendar.getTime().before(new Date())){

            //清除缓存
            redisService.del(RedisConstant.SMARTCARD_VISITOR_QR_CODE_CONTENT_CACHE_KEY + visitorId);
            return null;
        }
        String qrCodeContent = StringHandlerUtil.createQrCodeContent(smartCardQRCodeContentDTO.getEntrances() ,
                smartCardQRCodeContentDTO.getElevators(), smartCardQRCodeContentDTO.getProjectId(),
                smartCardQRCodeContentDTO.getStartDate(),smartCardQRCodeContentDTO.getValidTime(),smartCardQRCodeContentDTO.getBatchNumber(), smartCardQRCodeContentDTO.getProjectKey(),
                smartCardQRCodeContentDTO.getValidCount(),smartCardQRCodeContentDTO.getEntranceIdentifier(), smartCardQRCodeContentDTO.getUserId());

        miniProgramVisitorInfoVO.setContent(qrCodeContent);
        miniProgramVisitorInfoVO.setVisitorId(visitorId);
        miniProgramVisitorInfoVO.setTimeLimit(smartCardQRCodeContentDTO.getValidTime());

        return miniProgramVisitorInfoVO;
    }
}
